<template>
  <div class="app-container">
    <!--条件搜索表单-->
    <div style="margin-bottom: -20px">
      <el-form :inline="true" class="demo-form-inline">
        <el-form-item>
          <el-input v-model="searchObj.menuName" placeholder="菜单名称" />
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="el-icon-search" @click="getAll()">查询</el-button>
          <el-button icon="el-icon-refresh" @click="reset()">清空</el-button>
        </el-form-item>
      </el-form>
    </div>

    <!-- 工具栏 -->
    <div class="el-toolbar">
      <div class="el-toolbar-body" style="justify-content: flex-start; margin-top: 10px">
        <el-button v-if="hasPerm('sys:menu:save')" type="primary" icon="el-icon-plus" @click="openEdit(null, true)">新增</el-button>
        <el-button type="primary" icon="el-icon-arrow-down" @click="expandAll(true)">全部展开</el-button>
        <el-button type="primary" icon="el-icon-arrow-up" @click="expandAll(false)">全部折叠</el-button>
      </div>
    </div>

    <!-- banner列表 :data="list"表示遍历list数组 stripe条纹 -->
    <el-table
      ref="menuTableRef"
      v-loading="loading"
      element-loading-text="正在努力加载数据中..."
      :data="list"
      :border="false"
      stripe
      row-key="id"
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
      :expand-row-keys="expandedKeys"
      style="margin: 15px 0px"
    >
      <el-table-column prop="menuName" fixed="left" label="菜单名称" min-width="200" show-overflow-tooltip />
      <el-table-column prop="type" label="菜单类型" min-width="100" :filters="menuTypeOptions" :filter-method="filterHandler">
        <template slot-scope="scope">
          <el-tag v-if="scope.row.type === 0" type="default">目录</el-tag>
          <el-tag v-if="scope.row.type === 1" type="success">菜单</el-tag>
          <el-tag v-if="scope.row.type === 2" type="info">按钮</el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="icon" label="菜单图标">
        <template slot-scope="scope">
          <i :class="scope.row.icon" size="40" />
        </template>
      </el-table-column>
      <el-table-column prop="path" label="菜单路径" show-overflow-tooltip />
      <el-table-column prop="component" label="组件地址" show-overflow-tooltip />
      <el-table-column prop="redirect" label="跳转地址" show-overflow-tooltip />
      <el-table-column prop="perms" label="权限标识" show-overflow-tooltip />
      <el-table-column prop="priority" label="优先级" min-width="100" sortable />
      <el-table-column prop="visible" label="是否隐藏" min-width="120" sortable :filters="visibleOptions" :filter-method="filterHandler">
        <template slot-scope="scope">
          <el-tag v-if="scope.row.visible === 0" type="success">否</el-tag>
          <el-tag v-if="scope.row.visible === 1" type="danger">是</el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="status" label="状态" min-width="100" sortable :filters="statusOptions" :filter-method="filterHandler">
        <template slot-scope="scope">
          <el-switch v-model="scope.row.status" :active-value="0" :inactive-value="1" @change="handleStatusChange(scope.row)" />
        </template>
      </el-table-column>
      <el-table-column prop="remark" label="备注" show-overflow-tooltip />
      <el-table-column prop="createTime" label="创建时间" min-width="100" sortable show-overflow-tooltip />

      <!-- 操作 -->
      <el-table-column v-if="hasPerm('sys:menu:save', 'sys:menu:update', 'sys:menu:delete')" label="操作" fixed="right" width="200" align="center">
        <template slot-scope="scope">
          <el-link v-if="hasPerm('sys:menu:save')" type="primary" icon="el-icon-plus" @click="openEdit(scope.row, true)">添加</el-link>
          <el-divider v-if="hasPerm('sys:menu:save')" direction="vertical" />
          <el-link v-if="hasPerm('sys:menu:update')" type="success" icon="el-icon-edit" @click="openEdit(scope.row, false)">修改</el-link>
          <el-divider v-if="hasPerm('sys:menu:update')" direction="vertical" />
          <el-link v-if="hasPerm('sys:menu:delete')" type="danger" icon="el-icon-remove" @click="remove(scope.row)">删除</el-link>
        </template>
      </el-table-column>
    </el-table>

    <!-- 表单 -->
    <el-dialog v-if="hasPerm('sys:menu:save', 'sys:menu:update')" :title="dialogTitle" :visible.sync="visible" @close="close('menuForm')">
      <el-form ref="menuForm" :model="menu" :rules="rules" label-width="100px">
        <el-row :gutter="10">
          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
            <el-form-item label="所属上级" prop="parentId">
              <el-cascader
                ref="parentCascader"
                v-model="menu.parentId"
                :options="list"
                :props="{ value: 'id', label: 'menuName', checkStrictly: true }"
                clearable
                filterable
                placeholder="请选择上级"
                style="width: 100%"
              >
                <template slot-scope="{ node, data }">
                  <span>{{ data.menuName }}</span>
                  <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
                </template>
              </el-cascader>
            </el-form-item>
          </el-col>

          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
            <el-form-item label="菜单名称" prop="menuName" required>
              <el-input v-model="menu.menuName" placeholder="请输入菜单名称" />
            </el-form-item>
          </el-col>

          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
            <el-form-item label="菜单类型" prop="type">
              <el-radio-group v-model="menu.type" size="default">
                <el-radio-button v-for="item in menuTypeOptions" :key="item.value" :label="item.value">{{ item.text }}</el-radio-button>
              </el-radio-group>
            </el-form-item>
          </el-col>

          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
            <el-form-item v-if="activeItem.isPath" prop="path" :required="activeItem.isPath">
              <template #label>
                路由地址
                <el-tooltip class="item" effect="dark" content="示例: sys" placement="top">
                  <i class="el-icon-question" size="40" />
                </el-tooltip>
              </template>
              <el-input v-model="menu.path" placeholder="请输入路由地址" />
            </el-form-item>
          </el-col>

          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
            <el-form-item v-if="activeItem.isComponent" prop="component" :required="activeItem.isComponent">
              <template #label>
                组件地址
                <el-tooltip class="item" effect="dark" content="示例: Layout" placement="top">
                  <i class="el-icon-question" size="40" />
                </el-tooltip>
              </template>
              <el-input v-model="menu.component" placeholder="请输入组件地址" />
            </el-form-item>
          </el-col>

          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
            <el-form-item v-if="activeItem.isRedirect" prop="redirect">
              <template #label>
                重定向
                <el-tooltip class="item" effect="dark" content="示例: /sys/user" placement="top">
                  <i class="el-icon-question" size="40" />
                </el-tooltip>
              </template>
              <el-input v-model="menu.redirect" placeholder="请输入重定向地址" />
            </el-form-item>
          </el-col>

          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
            <el-form-item v-if="activeItem.isVisible" label="是否显示" prop="visible">
              <el-select v-model="menu.visible" style="width: 100%" placeholder="请选择是否显示">
                <el-option v-for="item in visibleOptions" :key="item.value" :label="item.text" :value="item.value" />
              </el-select>
            </el-form-item>
          </el-col>

          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
            <el-form-item v-if="activeItem.isPerms" prop="perms">
              <template #label>
                权限标识
                <el-tooltip class="item" effect="dark" content="示例: sys:user:list" placement="top">
                  <i class="el-icon-question" size="40" />
                </el-tooltip>
              </template>
              <el-input v-model="menu.perms" placeholder="请输入权限标识" />
            </el-form-item>
          </el-col>

          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
            <el-form-item v-if="activeItem.isIcon" label="菜单图标" prop="icon">
              <el-select v-model="menu.icon" placeholder="请选择菜单图标" filterable style="width: 100%">
                <el-option v-for="icon in iconList" :key="icon" :label="icon" :value="icon"> <i :class="`${icon}`" /> {{ icon }} </el-option>
              </el-select>
            </el-form-item>
          </el-col>

          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
            <el-form-item label="状态" prop="status">
              <el-select v-model="menu.status" style="width: 100%" placeholder="请选择状态">
                <el-option v-for="item in statusOptions" :key="item.value" :label="item.text" :value="item.value" />
              </el-select>
            </el-form-item>
          </el-col>

          <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8">
            <el-form-item label="优先级" prop="priority">
              <el-input-number v-model="menu.priority" controls-position="right" placeholder="请输入优先级" style="width: 100%" />
            </el-form-item>
          </el-col>

          <el-col>
            <el-form-item label="菜单备注" prop="remark">
              <el-input v-model="menu.remark" :rows="3" type="textarea" placeholder="请输入备注" maxlength="255" show-word-limit />
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="close('menuForm')">取 消</el-button>
        <el-button type="primary" @click="save('menuForm')">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
// 引入api接口定义的js文件
import menuApi from '@/api/sys/menu'
import iconList from '@/views/sys/menu/icon'
import { getItem } from './menu'

export default {
  data() {
    // 定义变量和初始值
    return {
      iconList: iconList,
      statusOptions: [
        { value: 0, text: '正常' },
        { value: 1, text: '停用' }
      ],
      menuTypeOptions: [
        { value: 0, text: '目录' },
        { value: 1, text: '菜单' },
        { value: 2, text: '按钮' }
      ],
      visibleOptions: [
        { value: 0, text: '显示' },
        { value: 1, text: '隐藏' }
      ],

      // 列表相关
      loading: false,
      searchObj: {}, // 条件封装对象
      list: [], // 列表
      ids: [], // ID集合
      expandedKeys: [], // 默认展开菜单列表

      // 表单相关
      dialogTitle: '',
      visible: false,
      menu: {
        parentId: undefined,
        menuName: '',
        type: 0,
        path: '',
        component: '',
        redirect: '',
        visible: 0,
        perms: '',
        icon: 'el-icon-document',
        status: 0,
        priority: 0,
        remark: ''
      },

      // 验证规则
      rules: {
        menuName: [{ required: true, message: '菜单名称不能为空', trigger: 'blur' }],
        path: [{ required: true, message: '路由地址不能为空', trigger: 'blur' }],
        component: [{ required: true, message: '组件地址不能为空', trigger: 'blur' }]
      }
    }
  },

  // 计算函数
  computed: {
    activeItem() {
      return getItem(this.menu.type)
    }
  },

  // 创建函数
  created() {
    this.getAll()
  },

  // 方法
  methods: {
    // 加载列表数据
    getAll() {
      this.loading = true
      menuApi
        .getList(this.searchObj)
        .then((response) => {
          this.list = response.data
        })
        .finally(() => {
          this.loading = false
        })
    },

    // 行内筛选处理
    filterHandler(value, row, column) {
      const property = column['property']
      return row[property] === value
    },

    // 删除用户信息
    remove(row) {
      this.$confirm('此操作将永久删除菜单信息, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        menuApi.deleteById(row.id).then((resp) => {
          this.$message.success('删除成功!')
          this.getAll()
        })
      })
    },

    // 复选框选中
    handleSelectionChange(r) {
      // 得到选中的id
      this.ids = r.map((v) => v.id)
    },

    // 改变状态
    handleStatusChange(row) {
      const text = row.status === 0 ? '正常' : '停用'
      this.$confirm(`此操作将修改 '${row.menuName}' 状态为 '${text}', 是否继续?`, '菜单状态修改', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      })
        .then(() => {
          menuApi
            .updateStatus(row.id, row.status)
            .then((resp) => {
              this.$message.success('操作成功！')
            })
            .catch(() => {
              row.status = row.status === 0 ? 1 : 0
            })
        })
        .catch(() => {
          row.status = row.status === 0 ? 1 : 0
        })
    },

    setAllExpand(arr, state) {
      arr.forEach((i) => {
        // toggleRowExpansion(i, isExpand)用于多选表格，切换某一行的选中状态
        // 如果使用了第二个参数，则是设置这一行选中与否（selected 为 true 则选中）
        this.$refs.menuTableRef.toggleRowExpansion(i, state)
        if (i.children) {
          this.setAllExpand(i.children, state)
        }
      })
    },

    // 全部展开/折叠
    expandAll(expand) {
      this.$nextTick(() => {
        this.setAllExpand(this.list, expand)
      })
    },

    // 新增
    openEdit(row, isEdit) {
      this.visible = true
      if (isEdit) {
        // 新增
        this.dialogTitle = '新增菜单'
        this.menu.type = row ? (row.type === 0 ? 1 : 2) : 0
        this.menu.parentId = row ? row.id : 0
        this.menu.priority = this.list.length + 2
      } else {
        // 编辑
        this.dialogTitle = '编辑菜单'
        this.menu.type = row.type === 0 ? 1 : 2
        this.menu.parentId = row.id

        menuApi.getById(row.id).then((res) => {
          Object.assign(this.menu, res.data)
        })
      }
    },

    // 关闭
    close(form) {
      this.visible = false
      this.$refs[form].resetFields()
    },

    // 保存
    save(form) {
      this.$refs[form].validate((valid) => {
        if (valid) {
          this.menu.parentId = this.$refs['parentCascader'].getCheckedNodes()[0]?.value ?? 0
          const apiCall = this.menu.id ? menuApi.update(this.menu) : menuApi.save(this.menu)
          apiCall.then(() => {
            this.$message.success('保存成功!')
            this.getAll()
            this.close(form)
          })
        }
      })
    },

    // 批量删除
    batchDelete() {
      if (this.ids.length > 0) {
        this.$confirm('此操作将永久删除菜单信息,是否继续?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        })
          // 确定执行then方法
          .then(() => {
            menuApi.batchDelete(this.ids).then((resp) => {
              this.$message.success('删除成功!')
              this.getAll()
            })
          })
      } else {
        this.$message.warning('至少选择一条数据!')
      }
    },

    // 重置
    reset() {
      this.searchObj = {}
      this.getAll()
    }
  }
}
</script>

<style></style>
